package com.weifly.weistock.trade.config.impl;

import com.weifly.weistock.core.common.StockException;
import com.weifly.weistock.core.event.AbstractEventService;
import com.weifly.weistock.trade.config.AccountConfigDto;
import com.weifly.weistock.trade.config.AllStockConfig;
import com.weifly.weistock.trade.config.StockConfigDto;
import com.weifly.weistock.trade.config.StockConfigService;
import org.apache.commons.io.IOUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 读取股票配置
 *
 * @author weifly
 * @since 2018/8/20
 */
public class XmlFileStockConfigService extends AbstractEventService implements StockConfigService {

    private static final String ELE_CONFIG = "config";
    private static final String ELE_ACCOUNT = "account";
    private static final String ELE_SERVER_IP = "serverIp";
    private static final String ELE_SERVER_PORT = "serverPort";
    private static final String ELE_VERSION = "version";
    private static final String ELE_YYB_ID = "yybID";
    private static final String ELE_ACCOUNT_NO = "accountNo";
    private static final String ELE_TRADE_ACCOUNT = "tradeAccount";
    private static final String ELE_JY_PASSWORD = "jyPassword";
    private static final String ELE_TX_PASSWORD = "txPassword";
    private static final String ELE_TRADE = "trade";
    private static final String ELE_STOCK_CODE = "stockCode";
    private static final String ELE_STOCK_NAME = "stockName";
    private static final String ELE_EXCHANGE_ID = "exchangeId";
    private static final String ELE_CREDIT_BUY = "creditBuy";
    private static final String ELE_OPEN = "open";
    private static final String ELE_BASE_PRICE = "basePrice";
    private static final String ELE_TRADE_UNIT = "tradeUnit";
    private static final String ELE_STEP = "step";
    private static final String ELE_GRID_PRICE_LIST = "gridPriceList";
    private static final String ELE_PRICE = "price";
    private Logger logger = LoggerFactory.getLogger(XmlFileStockConfigService.class);

    private String configPath; // 配置文件路径

    public void setConfigPath(String configPath) {
        this.configPath = configPath;
    }

    /**
     * 从xml文件加载配置信息
     */
    @Override
    public AllStockConfig parseConfig() {
        AllStockConfig allStockConfig = new AllStockConfig();
        if(this.configPath==null || this.configPath.trim().isEmpty()){
            logger.warn("没有配置configPath");
            return allStockConfig;
        }
        File configFile = new File(this.configPath);
        if(!configFile.exists()){
            logger.warn("配置文件不存在: " + this.configPath);
            return allStockConfig;
        }
        if(!configFile.isFile()){
            logger.warn("不是一个文件: " + this.configPath);
            return allStockConfig;
        }

        try{
            SAXReader reader = new SAXReader();
            Document document = reader.read(new File(this.configPath));
            Element rootEle = document.getRootElement();

            // 解析股票账号
            Element accountEle = rootEle.element(ELE_ACCOUNT);
            if(accountEle!=null){
                AccountConfigDto accountCfg = new AccountConfigDto();
                accountCfg.setServerIp(accountEle.elementText(ELE_SERVER_IP));
                accountCfg.setServerPort(Integer.valueOf(accountEle.elementText(ELE_SERVER_PORT)));
                accountCfg.setVersion(accountEle.elementText(ELE_VERSION));
                accountCfg.setYybID(Integer.valueOf(accountEle.elementText(ELE_YYB_ID)));
                accountCfg.setAccountNo(accountEle.elementText(ELE_ACCOUNT_NO));
                accountCfg.setTradeAccount(accountEle.elementText(ELE_TRADE_ACCOUNT));
                accountCfg.setJyPassword(accountEle.elementText(ELE_JY_PASSWORD));
                accountCfg.setTxPassword(accountEle.elementText(ELE_TX_PASSWORD));
                allStockConfig.setAccountConfig(accountCfg);
            }

            // 解析股票配置
            List<Element> tradeEleList = rootEle.elements(ELE_TRADE);
            if(tradeEleList!=null){
                List<StockConfigDto> stockCfgList = new ArrayList<>();
                for(Element tradeEle : tradeEleList){
                    StockConfigDto stockConfig = new StockConfigDto();
                    stockConfig.setStockCode(tradeEle.element(ELE_STOCK_CODE).getText());
                    stockConfig.setStockName(tradeEle.element(ELE_STOCK_NAME).getText());
                    Element exchangeIdEle = tradeEle.element(ELE_EXCHANGE_ID);
                    if(exchangeIdEle!=null){
                        stockConfig.setExchangeId(exchangeIdEle.getText());
                    }
                    stockConfig.setOpen("true".equals(tradeEle.elementText(ELE_OPEN)));
                    stockConfig.setCreditBuy("true".equals(tradeEle.element(ELE_CREDIT_BUY).getText()));
                    stockConfig.setBasePrice(Double.valueOf(tradeEle.element(ELE_BASE_PRICE).getText()));
                    stockConfig.setTradeUnit(Integer.valueOf(tradeEle.element(ELE_TRADE_UNIT).getText()));
                    stockConfig.setStep(Double.valueOf(tradeEle.elementText(ELE_STEP)));

                    Element gridPriceListEle = tradeEle.element(ELE_GRID_PRICE_LIST);
                    if(gridPriceListEle!=null){
                        List<Element> priceEleList = gridPriceListEle.elements(ELE_PRICE);
                        for(Element priceEle : priceEleList){
                            stockConfig.getGridPriceList().add(Double.valueOf(priceEle.getText()));
                        }
                    }

                    stockCfgList.add(stockConfig);
                    logger.info("加载股票配置：" + stockConfig.getStockCode());
                }
                allStockConfig.setStockConfigList(stockCfgList);
            }

            return allStockConfig;
        }catch(DocumentException e){
            logger.error("", e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public void saveConfig(AllStockConfig allStockConfig) {
        DocumentFactory factory = DocumentFactory.getInstance();

        Document document = factory.createDocument();
        document.setXMLEncoding("UTF8");

        Element rootEle = factory.createElement(ELE_CONFIG);
        document.setRootElement(rootEle);

        // 写入股票账号
        if(allStockConfig.getAccountConfig()!=null){
            AccountConfigDto accountConfig = allStockConfig.getAccountConfig();
            Element accountEle = factory.createElement(ELE_ACCOUNT);
            accountEle.add(this.createEle(factory, ELE_SERVER_IP, accountConfig.getServerIp()));
            accountEle.add(this.createEle(factory, ELE_SERVER_PORT, accountConfig.getServerPort()));
            accountEle.add(this.createEle(factory, ELE_VERSION, accountConfig.getVersion()));
            accountEle.add(this.createEle(factory, ELE_YYB_ID, accountConfig.getYybID()));
            accountEle.add(this.createEle(factory, ELE_ACCOUNT_NO, accountConfig.getAccountNo()));
            accountEle.add(this.createEle(factory, ELE_TRADE_ACCOUNT, accountConfig.getTradeAccount()));
            accountEle.add(this.createEle(factory, ELE_JY_PASSWORD, accountConfig.getJyPassword()));
            accountEle.add(this.createEle(factory, ELE_TX_PASSWORD, accountConfig.getTxPassword()));
            rootEle.add(accountEle);
        }

        // 写入股票配置
        List<StockConfigDto> stockConfigList = allStockConfig.getStockConfigList();
        if(stockConfigList!=null && stockConfigList.size()>0){
            for(StockConfigDto stockConfig : stockConfigList){
                Element tradeEle = factory.createElement(ELE_TRADE);
                tradeEle.add(this.createEle(factory, ELE_STOCK_CODE, stockConfig.getStockCode()));
                tradeEle.add(this.createEle(factory, ELE_STOCK_NAME, stockConfig.getStockName()));
                tradeEle.add(this.createEle(factory, ELE_EXCHANGE_ID, stockConfig.getExchangeId()));
                tradeEle.add(this.createEle(factory, ELE_OPEN, stockConfig.getOpen()));
                tradeEle.add(this.createEle(factory, ELE_CREDIT_BUY, stockConfig.getCreditBuy()));
                tradeEle.add(this.createEle(factory, ELE_BASE_PRICE, stockConfig.getBasePrice()));
                tradeEle.add(this.createEle(factory, ELE_TRADE_UNIT, stockConfig.getTradeUnit()));
                tradeEle.add(this.createEle(factory, ELE_STEP, stockConfig.getStep()));
                Element gridPriceListEle = factory.createElement(ELE_GRID_PRICE_LIST);
                for(Double price : stockConfig.getGridPriceList()){
                    gridPriceListEle.add(this.createEle(factory, ELE_PRICE, price));
                }
                tradeEle.add(gridPriceListEle);
                rootEle.add(tradeEle);
            }
        }

        FileOutputStream output = null;
        try{
            output = new FileOutputStream(this.configPath);
            OutputFormat format = new OutputFormat("  ", true, "UTF8");
            XMLWriter writer = new XMLWriter(output, format);
            writer.write(document);
            writer.close();
        }catch(IOException e){
            throw new RuntimeException(e);
        }finally {
            IOUtils.closeQuietly(output);
        }
    }

    private Element createEle(DocumentFactory factory, String elementName, Object text){
        Element ele = factory.createElement(elementName);
        if(text!=null){
            ele.setText(text.toString());
        }
        return ele;
    }
}
